/**
 * 测试FHOPE算法的同态加乘运算
 */
package com.expriment.polynomial;

import java.io.IOException;

import com.algorithm.core.FHOPEAlgorithm;

/**
 * @author 汪海伟
 * <h1>这个类中完成了对FHOPE算法同态加和同态乘的性能测试</h1>
 * <p>具体做法是定义两个函数addition(double ciper[], int numOfShares, int itemsNum),和multiplication(double ciper[], int numOfShares, int exponent)</p>
 *
 */
public class Polynomial {

    private int numOfShares = 0;
    private double[][] keys = null;
    public Polynomial(int numOfShares, double[][] keys, double sens){
        this.numOfShares = numOfShares;
        this.keys = keys;
    }

    /**
     * 
     * @param ciper 操作数
     * @param numOfShares 密文分片的个数
     * @param itemsNum 累加的次数
     * @return 返回对ciperA累加itemsNum次的结果，该结果是一个密文。
     */
    public double[] addition(double ciper[], int itemsNum){
        double[] result = new double[numOfShares];
        for(int i = 0; i < itemsNum; i++){
            for(int j = 0; j < numOfShares; j++){
                result[j] = result[j] + ciper[j];
            }
        }
        return result;
    }

    /**
     * 
     * @param ciper 操作数
     * @param numOfShares  密文分片的个数
     * @param exponent  指数的次，也是乘法运算的次数
     * @return  返回对ciper累乘的结果。
     * @throws IOException 
     */
    public double[] multiplication(double ciper[], int exponent){
        FHOPEAlgorithm fhopeAlg = new FHOPEAlgorithm();
        double[] result = new double[numOfShares];
        //用二维数组构造一个中间结果。
        double[][] elements = new double[numOfShares][numOfShares];
        //将密文操作数保存起来
        double[] tempResult = (double[])ciper.clone();
        for(int exp = 0; exp < exponent; exp++){
            //i代表行，j代表列
            for(int i = 0; i < numOfShares; i++){
                for(int j = 0; j < numOfShares; j++){
                    elements[i][j] = tempResult[i] * ciper[j];
                }
                result[i] = fhopeAlg.decryptFunc(elements[i], keys, numOfShares);
            }
            //tempResult保存当前的乘积
            System.arraycopy(result, 0, tempResult, 0, numOfShares);
        }
        return result;
    }
    

    public static void main(String[] args) throws InterruptedException{
        //首先准备一些测试的材料
        int num = 5;      //分片个数设置为5个
        double sens = 0.00000001;  //精度控制在0.1
        FHOPEAlgorithm fhope = new FHOPEAlgorithm();
        double[][] keys = fhope.keyGenerate(num);   //生成密钥
        double[][] noises = fhope.noiseGenerate(num, sens, keys);   //生成随机噪声
        double plain = 10;     //定义一个明文值
        //结合已有的材料，生成一个对应的密文
        double[] ciper = fhope.encryptFunc(plain, keys, noises, num);
        //接下来，在密文上执行N次的累加和累乘，看看结果和时间。
        Polynomial pl = new Polynomial(num, keys, sens);
        //double[] resultCiper = pl.multiplication(ciper, 3);
        //System.out.println(fhope.decryptFunc(resultCiper, keys, num));  //测试计算的结果和预期的是否一致
        ResultOfPolynomial output = new ResultOfPolynomial();
        output.createSheet();
        long start = 0;
        long end = 0;
        long timeOfAdd = 0;
        long timeOfMulti = 0;
        int maxN = 30;
        for(int i = 10; i <= maxN; i = i + 10){
            start = System.nanoTime();
            pl.addition(ciper, i);
            end = System.nanoTime();
            timeOfAdd = end - start;

            Thread.sleep(100);

            start = System.nanoTime();
            pl.multiplication(ciper, i);
            end = System.nanoTime();
            timeOfMulti = end - start;

            output.outputToExcel(i, timeOfAdd, timeOfMulti);
        }
    }

}
